-
Notifications
You must be signed in to change notification settings - Fork 468
feat: Add rate limiting to identity search endpoint #6438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Add rate limiting to identity search endpoint #6438
Conversation
- Backend: Add ScopedRateThrottle to IdentityViewSet (30 req/min) - Frontend: Increase debounce from 500ms to 750ms - Config: Add IDENTITY_SEARCH_THROTTLE_RATE env variable - Tests: Add test for identity search throttling Fixes aggressive API requests when searching for identities.
|
@smy-637q is attempting to deploy a commit to the Flagsmith Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds rate limiting to the identity search endpoint to prevent aggressive API requests. It includes backend throttling via Django REST Framework's ScopedRateThrottle, a configurable environment variable for the rate limit, frontend debounce increase, and a test to verify throttling behavior.
- Backend throttling implementation with
ScopedRateThrottleat 30 requests/minute - Frontend debounce increase from 500ms to 750ms across all search components
- Configurable rate limit via
IDENTITY_SEARCH_THROTTLE_RATEenvironment variable
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| api/environments/identities/views.py | Adds ScopedRateThrottle with identity_search scope to IdentityViewSet |
| api/app/settings/common.py | Adds IDENTITY_SEARCH_THROTTLE_RATE environment variable configuration (default: 30/min) |
| api/tests/unit/environments/identities/test_unit_identities_views.py | Adds test to verify identity search throttling behavior |
| frontend/common/useDebouncedSearch.ts | Increases debounce time from 500ms to 750ms for all search operations |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_identity_search_is_throttled( | ||
| admin_client: APIClient, | ||
| environment: Environment, | ||
| settings, |
Copilot
AI
Dec 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is missing the reset_cache fixture parameter which is used in other throttle tests to ensure proper cache cleanup between tests. DRF's ScopedRateThrottle uses Django's cache backend to track request counts, and without cache clearing, throttle state could persist between tests causing flaky test failures.
Add reset_cache to the function parameters (see examples in api/tests/integration/custom_auth/end_to_end/test_custom_auth_integration.py lines 486-491 and 527-533).
| settings, | |
| settings, | |
| reset_cache, |
| const [debounceTime, setDebounceTime] = useState(750) | ||
|
|
||
| useEffect(() => { | ||
| setDebounceTime(searchInput.length < 1 ? 0 : 500) | ||
| setDebounceTime(searchInput.length < 1 ? 0 : 750) |
Copilot
AI
Dec 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Increasing the debounce time from 500ms to 750ms will affect all components using useDebouncedSearch, not just identity search. This includes:
- AuditLog.tsx
- ConversionEventSelect.tsx
- CreateSegment.tsx (segment search)
- SegmentsPage.tsx
- SplitTestPage.tsx
- UserPage.tsx
- UsersPage.tsx (identity search)
- TableValueFilter.tsx
While this may be acceptable to reduce API calls globally, consider whether a 250ms increase is appropriate for all these use cases. If the intent is to only throttle identity search, consider creating a separate hook like useDebouncedIdentitySearch with the higher debounce time, or make the debounce time configurable via a parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zaimwa9 are you able to chime in here - do you think this is something we need to be concerned about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@1-23-smy thanks for the changes, could you explain the rationale behind the increase of the debounce? If this does not conflict with the extra throttling we'd better stick to 500. We aligned on 500 being the right UX time
- Use get_throttles() method to conditionally apply throttle only to 'list' action - Update test to use mocker.patch and reset_cache fixture for proper cleanup - Follow existing patterns from FFAdminUserViewSet and OrganisationViewSet
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
|
@1-23-smy could you check the unit test failures here please? |
|
matthewelwell Sure, I will look into it |
The test.py settings file overrides DEFAULT_THROTTLE_RATES from common.py, so identity_search scope was missing in the test environment.
@matthewelwell Could you review once ? |
Thanks - I'll take a look, but you do have some conflicts that also need resolving please. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6438 +/- ##
=======================================
Coverage 98.09% 98.09%
=======================================
Files 1293 1293
Lines 46610 46624 +14
=======================================
+ Hits 45722 45736 +14
Misses 888 888 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@matthewelwell I have fixed the conflicts. Could you please review once ? |
Zaimwa9
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution 👍 . 2 comments, the most important one would be to stick with the previous debounce time if you don't mind
| const [debounceTime, setDebounceTime] = useState(750) | ||
|
|
||
| useEffect(() => { | ||
| setDebounceTime(searchInput.length < 1 ? 0 : 500) | ||
| setDebounceTime(searchInput.length < 1 ? 0 : 750) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@1-23-smy thanks for the changes, could you explain the rationale behind the increase of the debounce? If this does not conflict with the extra throttling we'd better stick to 500. We aligned on 500 being the right UX time
api/environments/identities/views.py
Outdated
| """ | ||
| if getattr(self, "action", None) == "list": | ||
| return [ScopedRateThrottle()] | ||
| return [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though the impact is minimal, i would suggest to return the global default throttle super().get_throttles here (defaulting to DEFAULT_THROTTLE_CLASSES). Similarly to what we did here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I have reverted debounce from 750ms back to 500ms (agreed UX time).
- Updated get_throttles() to return super().get_throttles() for non-list actions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks a lot! Just some conflicts to fix and we should be good to enable the workflows and get it over the line. Again, thanks for the contribution, we appreciate!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! the conflicts should now be resolved.
Let me know if there's anything else you'd like me to adjust!
- Revert frontend debounce from 750ms back to 500ms (agreed UX time) - Return super().get_throttles() for non-list actions so global default throttle classes still apply
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
This PR is being reviewed by Cursor Bugbot
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
…entity-search-rate-limiting
Zaimwa9
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good to me, I allowed myself to fix some loss - probably while fixing conflicts. Thanks for the contribution!
ScopedRateThrottletoIdentityViewSet(30 req/min)IDENTITY_SEARCH_THROTTLE_RATEenv variableThis fixes aggressive API requests when searching for identities.
Thanks for submitting a PR! Please check the boxes below:
docs/if required so people know about the featureChanges
Backend Changes
api/environments/identities/views.pyAdded
ScopedRateThrottletoIdentityViewSetwith scopeidentity_searchapi/app/settings/common.pyAdded configurable
IDENTITY_SEARCH_THROTTLE_RATEenvironment variable (default:30/min)Frontend Changes
frontend/common/useDebouncedSearch.tsIncreased debounce time from 500ms to 750ms to reduce request frequency during typing
Configuration
The rate limit can be customized via environment variable:
How did you test this code?
Unit Tests
test_identity_search_is_throttledinapi/tests/unit/environments/identities/test_unit_identities_views.pyManual Testing